<?php


namespace App\Service;

use App\Constants\ErrorCode;
use App\Exception\BusinessException;
use App\Library\Common;
use App\Model\Aftersale;
use App\Model\AftersaleProduct;
use App\Model\FlyOrder;
use App\Model\FlyOrderProduct;
use App\Model\ShopSendAddress;
use Hyperf\Database\Model\Builder;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\Snowflake\IdGeneratorInterface;
use Hyperf\Utils\ApplicationContext;
use Hyperf\Validation\Contract\ValidatorFactoryInterface;
use Hyperf\Validation\Rule;
use App\Service\AftersaleSetService;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use const Zipkin\Tags\ERROR;

/**
 * Class AftersaleService
 * @package App\Service
 */
class AftersaleService extends BaseService
{

    /**
     * @Inject
     * @var PayService
     */
    private $pay;

    /**
     * @Inject
     * @var ShopSendAddressService
     */
    private $shopAddr;

    /**
     * @Inject
     * @var RequestInterface
     */
    private $request;

    /**
     * @Inject
     * @var FileinfoService
     */
    private $fileinfo;

    /**
     * @Inject
     * @var FlyOrderService
     */
    private $order;

    /**
     * @Inject
     * @var ValidatorFactoryInterface
     */
    private $valid;

    /**
     * @Inject
     * @var AftersaleSetService
     */
    private $afSet;


    // 待审核（用户提交）
    const STATUS_WAIT_CHECK = 1;
    // 已审核（商家审核）
    const STATUS_CHECKED = 2;
    // 已完成（售后处理完成）
    const STATUS_FINISHED = 3;
    // 已拒绝（商家拒绝售后处理）
    const STATUS_REFUSED = 4;
    // 已取消（用户取消）
    const STATUS_CANCEL = 5;

    const SEARCH_CAN_APPLY = 1; // 可申请：根据类型判断是否配置
    const SEARCH_PROCESSING = 2; // 处理中
    const SEARCH_RECORD = 3; // 申请记录

    const TYPE_REFUND = 1; // 仅退款
    const TYPE_REFUND_P = 2; // 退货退款
    const TYPE_SWAP = 3; // 换货
    const TYPE_REPAIR = 4; // 维修

    // 处理中
    const PROCESSING_STATUS = [
        self::STATUS_WAIT_CHECK,
        self::STATUS_CHECKED
    ];

    // 申请记录
    const RECORD_STATUS = [
        self::STATUS_FINISHED,
        self::STATUS_REFUSED,
        self::STATUS_CANCEL
    ];


    /**
     * 获取模型实例
     * @return mixed
     */
    public function getInstance()
    {
        return $this->getModelInstance();
    }

    /**
     * 用户售后单列表
     * @param int $user_id
     * @param int $type
     * @param string $key_word
     * @param int $order_or_af_id //  查询详情：订单或售后单
     * @return Builder
     */
    public function getAfList(int $user_id, int $type, $key_word = "", $order_or_af_id = 0): Builder
    {
        $af_fields = [
            Db::raw("ANY_VALUE(wf_fly_aftersale.af_id) as af_id"),
            Db::raw("ANY_VALUE(wf_fly_aftersale.af_sn) as af_sn"),
            Db::raw("ANY_VALUE(wf_fly_aftersale.order_id) as order_id"),
            Db::raw("ANY_VALUE(wf_fly_aftersale.af_status) as af_status"),
            Db::raw("ANY_VALUE(wf_fly_aftersale.af_type) as af_type"),
            Db::raw("ANY_VALUE(wf_fly_aftersale.apply_time) as apply_time"),
            Db::raw("ANY_VALUE(wf_fly_aftersale.check_time) as response_time"),
            Db::raw("ANY_VALUE(wf_fly_aftersale.is_refund) as is_refund"),
            Db::raw("ANY_VALUE(wf_fly_aftersale.refund_price) as refund_price"),
            Db::raw("ANY_VALUE(wf_fly_aftersale.refund_time) as refund_time"),
            Db::raw("ANY_VALUE(wf_fly_aftersale.refuse_reason) as refuse_reason"),
            Db::raw("ANY_VALUE(wf_fly_aftersale.is_back_coupon) as is_back_coupon"),
            Db::raw("ANY_VALUE(wf_fly_aftersale.is_back_delivery) as is_back_delivery"),
            Db::raw("ANY_VALUE(wf_fly_aftersale.back_coupon_price) as back_coupon_price"),
            Db::raw("ANY_VALUE(wf_fly_aftersale.back_delivery_price) as back_delivery_price"),
            Db::raw("ANY_VALUE(wf_fly_aftersale.check_time) as check_time"),
            Db::raw("ANY_VALUE(wf_fly_aftersale.shop_change_address_id) as shop_change_address_id"),
            Db::raw("ANY_VALUE(wf_fly_aftersale.voucher) as voucher"),
            Db::raw("ANY_VALUE(wf_fly_aftersale.af_reason_id) as af_reason_id"),
            Db::raw("ANY_VALUE(wf_fly_aftersale.af_reason) as af_reason"),
            Db::raw("ANY_VALUE(wf_fly_aftersale.desc) as description"),
            Db::raw("ANY_VALUE(wf_fly_aftersale.back_type) as back_type"),
            Db::raw("ANY_VALUE(wf_fly_aftersale.shop_address_id) as shop_address_id"),
            Db::raw("ANY_VALUE(wf_fly_aftersale.af_order_style) as af_order_style"),
            Db::raw("ANY_VALUE(wf_fly_order.virtual_form_info) as virtual_form_info")
        ];
        switch ($type) {
            case self::SEARCH_PROCESSING: // 处理中
                $instance = make(Aftersale::class)
                    ->with(['with_products'])
                    ->leftJoin('fly_order', 'fly_aftersale.order_id', '=', 'fly_order.order_id')
                    ->leftJoin('fly_aftersale_products', 'fly_aftersale.af_id', '=', 'fly_aftersale_products.af_id')
                    ->leftJoin('fly_order_product', 'fly_aftersale_products.order_p_id', 'fly_order_product.id')
                    ->whereIn('af_status', self::PROCESSING_STATUS)
                    ->where(function ($where) use ($key_word, $order_or_af_id, $user_id) {
                        $where->where('fly_aftersale.user_id', '=', $user_id);
                        // 订单详情
                        if (!empty($order_or_af_id)) {
                            $where->where('fly_order.order_id', '=', $order_or_af_id);
                        }
                        if (!empty($key_word)) {
                            $where->where('fly_order.shop_name', 'like', '%' . $key_word . '%')
                                ->orWhere('fly_order_product.product_name', 'like', '%' . $key_word . '%')
                                ->orWhere('fly_order.order_sn', 'like', '%' . $key_word . '%');
                        }
                    })
                    ->groupBy(['fly_aftersale.af_id'])
                    ->select($af_fields);
                break;
            case self::SEARCH_RECORD: // 申请记录
                $instance = make(Aftersale::class)
                    ->with(['with_products'])
                    ->leftJoin('fly_order', 'fly_aftersale.order_id', '=', 'fly_order.order_id')
                    ->leftJoin('fly_aftersale_products', 'fly_aftersale.af_id', '=', 'fly_aftersale_products.af_id')
                    ->leftJoin('fly_order_product', 'fly_aftersale_products.order_p_id', 'fly_order_product.id')
                    ->whereIn('af_status', self::RECORD_STATUS)
                    ->where(function ($where) use ($key_word, $order_or_af_id, $user_id) {
                        $where->where('fly_aftersale.user_id', '=', $user_id);
                        // 售后详情
                        if (!empty($order_or_af_id)) {
                            $where->where('fly_order.order_id', '=', $order_or_af_id);
                        }
                        if (!empty($key_word)) {
                            $where->where('fly_order.shop_name', 'like', '%' . $key_word . '%')
                                ->orWhere('fly_order_product.product_name', 'like', '%' . $key_word . '%')
                                ->orWhere('fly_order.order_sn', 'like', '%' . $key_word . '%');
                        }
                    })
                    ->groupBy(['fly_aftersale.af_id'])
                    ->select($af_fields);
                break;
            default: // 可申请
                $instance = $this->order->getInstance()
                    ->where(['fly_order.is_pay' => 1, 'fly_order.order_style' => 1])
                    ->with(['with_can_apply_food_af_products', 'with_can_apply_af_products'])
                    ->leftJoin('fly_order_product', 'fly_order.order_id', '=', 'fly_order_product.order_id')
                    ->where(function ($where) use ($key_word, $user_id) {
                        $where->where('fly_order.user_id', '=', $user_id)
                            ->where('fly_order.is_pay', '=', 1);
                        if (!empty($key_word)) {
                            $where->where('fly_order.shop_name', 'like', '%' . $key_word . '%')
                                ->orWhere('fly_order_product.product_name', 'like', '%' . $key_word . '%')
                                ->orWhere('fly_order.order_sn', 'like', '%' . $key_word . '%');
                        }
                    })
                    ->where(function ($where) use ($order_or_af_id) {
                        // 订单详情
                        if (!empty($order_or_af_id)) {
                            $where->where('fly_order.order_id', '=', $order_or_af_id);
                        }
                    })
                    ->where(function ($where) {
                        $where->whereRaw("wf_fly_order_product.can_af_apply_duration*86400+paid_time >= " . time() . " and wf_fly_order_product.free_num>0 and wf_fly_order_product.support_af_types!=''") // 有效期内可申请
                        ->orWhereRaw("(wf_fly_order_product.can_af_apply_duration=-1 and wf_fly_order_product.free_num>0 and wf_fly_order_product.support_af_types!='')");
                    })
                    ->select([
                        Db::raw("ANY_VALUE(wf_fly_order.order_status) as order_status"),
                        Db::raw("ANY_VALUE(wf_fly_order.delivery_id) as delivery_id"),
                        Db::raw("ANY_VALUE(wf_fly_order.delivery_type) as delivery_type"),
                        Db::raw("ANY_VALUE(wf_fly_order.order_id) as order_id"),
                        Db::raw("ANY_VALUE(wf_fly_order.shop_id) as shop_id"),
                        Db::raw("ANY_VALUE(wf_fly_order.shop_name) as shop_name"),
                        Db::raw("ANY_VALUE(wf_fly_order.order_sn) as order_sn"),
                        Db::raw("ANY_VALUE(wf_fly_order.user_id) as user_id"),
                        Db::raw("ANY_VALUE(wf_fly_order.order_style) as order_style"),
                        Db::raw("ANY_VALUE(wf_fly_order.paid_price) as paid_price"),
                        Db::raw("ANY_VALUE(wf_fly_order_product.can_af_apply_duration) as can_af_apply_duration"),
                        Db::raw("ANY_VALUE(wf_fly_order_product.free_num) as free_num"),
                        Db::raw("ANY_VALUE(wf_fly_order_product.support_af_types) as support_af_types"),
                        Db::raw("ANY_VALUE(wf_fly_order.virtual_form_info) as virtual_form_info")
                    ])
                    ->groupBy(['fly_order_product.order_id']);
                // 美食订单申请售后不需判断售后申请期限和类型
                return $this->order->getInstance()
                    ->leftJoin('fly_order_product', 'fly_order.order_id', '=', 'fly_order_product.order_id')
                    ->whereIn('fly_order.order_status', [FlyOrderService::STATUS_FINISHED, FlyOrderService::STATUS_WAIT_RECEIVE])
                    ->where(['fly_order.is_pay' => 1])
                    ->whereIn('fly_order.order_style', [FlyOrderService::STYLE_SEAT, FlyOrderService::STYLE_ORDER])
                    ->with(['with_can_apply_food_af_products', 'with_can_apply_af_products'])
                    ->where(function ($where) use ($key_word, $user_id) {
                        $where->where('fly_order.user_id', '=', $user_id)
                            ->where('fly_order.is_pay', '=', 1);
                        if (!empty($key_word)) {
                            $where->where('fly_order.shop_name', 'like', '%' . $key_word . '%')
                                ->orWhere('fly_order_product.product_name', 'like', '%' . $key_word . '%')
                                ->orWhere('fly_order.order_sn', 'like', '%' . $key_word . '%');
                        }
                    })
                    ->where(function ($where) use ($order_or_af_id) {
                        // 订单详情
                        if (!empty($order_or_af_id)) {
                            $where->where('fly_order.order_id', '=', $order_or_af_id);
                        }
                    })
                    ->select([
                        Db::raw("ANY_VALUE(wf_fly_order.order_status) as order_status"),
                        Db::raw("ANY_VALUE(wf_fly_order.delivery_id) as delivery_id"),
                        Db::raw("ANY_VALUE(wf_fly_order.delivery_type) as delivery_type"),
                        Db::raw("ANY_VALUE(wf_fly_order.order_id) as order_id"),
                        Db::raw("ANY_VALUE(wf_fly_order.shop_id) as shop_id"),
                        Db::raw("ANY_VALUE(wf_fly_order.shop_name) as shop_name"),
                        Db::raw("ANY_VALUE(wf_fly_order.order_sn) as order_sn"),
                        Db::raw("ANY_VALUE(wf_fly_order.user_id) as user_id"),
                        Db::raw("ANY_VALUE(wf_fly_order.order_style) as order_style"),
                        Db::raw("ANY_VALUE(wf_fly_order.paid_price) as paid_price"),
                        Db::raw("ANY_VALUE(wf_fly_order_product.can_af_apply_duration) as can_af_apply_duration"),
                        Db::raw("ANY_VALUE(wf_fly_order_product.free_num) as free_num"),
                        Db::raw("ANY_VALUE(wf_fly_order_product.support_af_types) as support_af_types"),
                        Db::raw("ANY_VALUE(wf_fly_order.virtual_form_info) as virtual_form_info")
                    ])
                    ->groupBy(['fly_order_product.order_id'])->union($instance);

                break;
        }

        return $instance;
    }

    /**
     * 售后参数验证
     * @param int $user_id
     * @param bool $is_commit 默认提交验证 false:不验证原因
     * @return array
     */
    public function aftersaleVerify(int $user_id, $is_commit = true): array
    {
        $params = $this->request->inputs(['order_id', 'af_type', 'af_reason_id', 'desc', 'voucher', 'products']);

        // 订单商品
        $order = $this->order->getDetails($user_id, $params['order_id'] ?? 0);
        // 电商可申请列表、点餐可申请列表、订座订单没商品
        if (empty($order) || $order['is_pay'] == 0 || (empty($order['with_can_apply_af_products']) && empty($order['with_can_apply_food_af_products']) && $order['order_style'] != 2)) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, '订单不存在');
        }
        // 未支付已关闭不可申请
        if (in_array($order['order_status'], [1, 4]) || $order['paid_price'] == 0) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, "不支持售后");
        }
        // 订座订单（无商品售后）
        if ($order['order_style'] == FlyOrderService::STYLE_SEAT) {
            $res = $this->valid->make($params,
                [
                    'af_type' => ['required', 'integer', Rule::in([1])],// 仅支持退款
                    'af_reason_id' => ['nullable', 'integer'], // 售后原因
                    'desc' => ['nullable', 'max:150'],
                    'voucher.*' => ['nullable', 'integer']
                ]);
        } else {
            // 点餐、商城订单（有商品售后）
            $res = $this->valid->make($params,
                [
                    'af_type' => ['required', 'integer', Rule::in([1, 2, 3, 4])],
                    'af_reason_id' => ['nullable', 'integer'],
                    'desc' => ['nullable', 'max:150'],
                    'voucher.*' => ['nullable', 'integer'],
                    'products' => ['required'],
                    'products.*.sku_id' => ['required', 'integer'],
                    'products.*.quantity' => ['required', 'integer']
                ], [
                    'products.*.sku_id.required' => '未选择售后商品',
                    'products.*.quantity.required' => '未选择售后商品数量',
                ]);
            // 点餐仅支持仅退款售后
            if ($order['order_style'] == FlyOrderService::STYLE_ORDER && $params['af_type'] != 1) {
                throw new BusinessException(ErrorCode::NORMAL_ERROR, '不支持的点餐售后类型');
            }
        }

        if ($res->fails()) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, $res->errors()->first());
        }
        // 售后申请中判断
        if ($this->getModelInstance()->where(['order_id' => $params['order_id']])->whereIn('af_status', [AftersaleService::STATUS_WAIT_CHECK, AftersaleService::STATUS_CHECKED])->exists()) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, '申请失败,当前订单正在售后中!');
        }

        // 照片凭证
        $voucher = [];
        if (!empty($params['voucher']) && is_array($params['voucher'])) {
            // 判断凭证
            $files = $this->fileinfo->getFileinfo($params['voucher']);
            if (!empty($files)) {
                foreach ($files as $file) {
                    $voucher[] = [
                        'fileinfo_id' => $file['fileinfo_id'],
                        'url' => $file['url']
                    ];
                }
            }
        }
        // 指定类型订单的售后原因
        $af_reason = "";
        $model_type = $order['order_style'] == 1 ? AftersaleSetService::MODEL_TYPE_SHOP : ($order['order_style'] == 2 ? AftersaleSetService::MODEL_TYPE_FOOD_SEAT : AftersaleSetService::MODEL_TYPE_FOOD_ORDER);
        $af_reason_list = $this->afSet->getAfReason([$params['af_type']], $model_type);
        $af_duty_party = 0;
        // 选择售后原因
        if (isset($params['af_reason_id'])) {
            if ($params['af_reason_id'] != 0) {
                foreach ($af_reason_list as $r) {
                    if ($r['id'] == $params['af_reason_id']) {
                        $af_reason = $r['name'];// 售后原因
                        $af_duty_party = $r['duty_party'];
                    }
                }
            }
        }

        // 求取最短共有(无理由天数：仅针对商城订单)
        $support_no_reason_count = 0;// 申请支持无理由数量
        $best_no_reason_duration = 0;// 最短无理由期限
        foreach ($order['with_can_apply_af_products'] as $p) {
            if (in_array($p['sku_id'], array_column($params['products'], 'sku_id'))) {
                // 都支持无理由退货，且在有效期内
                if ($p['support_no_reason'] == 1 && $p['af_no_reason_duration'] * 86400 + $p['paid_time'] >= time()) {
                    // 无理由在退换货基础上
                    $support_no_reason_count++;
                    if ($best_no_reason_duration == 0) {
                        $best_no_reason_duration = $p['af_no_reason_duration'];// 无理由期限
                    } else {
                        if ($p['af_no_reason_duration'] < $best_no_reason_duration) {
                            $best_no_reason_duration = $p['af_no_reason_duration'];
                        }
                    }
                }
            }
        }
        // 所选商品都支持无理由售后时，售后原因列表出现无理由售后原因
        if ($order['order_style'] != 2 && count($params['products']) == $support_no_reason_count) {
            // 无理由在支持退换货的基础上
            if (in_array($params['af_type'], [2, 3])) {
                $af_reason_list[] = [
                    'id' => 0,
                    'name' => $best_no_reason_duration . "天无理由退换货"
                ];
            }
        }

        // 售后申请商品数量
        $sku_quantity = empty($params['products']) ? [] : array_column($params['products'], 'quantity', 'sku_id');
        if (empty($order['with_can_apply_af_products']) && $order['order_style'] == FlyShopService::STYLE_TYPE_SHOP) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, '没有可以售后的商品');
        }
        // 获取商家默认地址
        $shop_addr = $this->shopAddr->get_default_addr($order['shop_id']);
        // 订单是否发货
        $is_send = (in_array($order['delivery_type'], [1, 3]) && !empty($order['delivery_id'])) ? 1 : 0;
        // 优惠券是否适用
        $coupon_can_use = false;
        // 全退(订座、售后数量=下单数量)
        $refund_num = array_sum(array_column($params['products'], 'quantity'));
        $is_all_back = false;
        if (($order['order_style'] == FlyOrderService::STYLE_SEAT) || $order['product_num'] == $refund_num) {
            $is_all_back = true;
        }

        $af_order_info = [
            'order_status' => $order['order_status'],
            'delivery_id' => $order['delivery_id'],
            'delivery_type' => $order['delivery_type'],
            'shop_id' => $order['shop_id'],
            'shop_name' => $order['shop_name'],
            'shop_phone' => $shop_addr['phone'] ?? "",
            'shop_address_info' => $shop_addr['address_info'] ?? "",
            'shop_address_id' => $shop_addr['id'] ?? 0,// 收货地址 默认为商家地址
            'user_id' => $user_id,
            'user_name' => $order['link_name'],
            'user_phone' => $order['phone'],
            'user_address' => $order['address'],
            'user_address_id' => $order['address_id'],
            'af_sn' => $this->generateSn(),
            'af_type' => $params['af_type'],
            'apply_time' => time(),
            'is_back_delivery' => 1,
            'is_back_coupon' => 1,
            'back_delivery_price' => 0,
            'back_coupon_price' => 0,
            'can_back_delivery_price' => 0,
            'can_back_coupon_price' => 0,
            'voucher' => $is_commit ? json_encode($voucher) : $voucher,
            'af_reason_id' => $params['af_reason_id'] ?? 0,
            'af_reason' => $af_reason,
            'af_duty_party' => (0 === $params['af_reason_id'] ? AftersaleSetService::DUTY_PARTY_USER : $af_duty_party), // 售后责任方
            'is_delivery' => $is_send, // 申请时发货状态
            'coupon_can_use' => (int)$coupon_can_use, // 优惠券适用
            'is_all_back' => (int)$is_all_back, // 是否全退
            'desc' => $params['desc'] ?? "",
            'order_id' => $order['order_id'],
            'should_refund_price' => 0, // 至少应退款金额
            'products' => [],
            'reason_list' => $af_reason_list,
            'product_total' => 0,
            'product_num' => 0,
            'af_order_style' => $order['order_style'],
            'sku_name' => $order['sku_name'] ?? "",
            'sku_img' => $order['sku_img'] ?? "",
            'order_details' => $order
        ];
        // 提交表单过滤
        if ($is_commit && !in_array($params['af_reason_id'], array_column($af_order_info['reason_list'], 'id'))) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, '售后原因不存在');
        }

        // 替换美食售后申请商品
        if ($order['order_style'] == FlyOrderService::STYLE_ORDER) {
            unset($order['with_can_apply_af_products']);
            $order['with_can_apply_af_products'] = $order['with_can_apply_food_af_products'];
        }
        // 有商品售后：验证可申请售后商品
        foreach ($order['with_can_apply_af_products'] as $p) {
            // 申请售后商品
            if (in_array($p['sku_id'], array_column($params['products'], 'sku_id'))) {
                if ($p['free_num'] <= 0) {
                    throw new BusinessException(ErrorCode::NORMAL_ERROR, '无可用商品');
                }
                // 商城商品需判断：期限、售后类型、阶梯价
                if ($order['order_style'] == FlyOrderService::STYLE_SHOP) {
                    // 判断是否超过售后服务期限
                    if (isset($params['af_reason_id'])) {
                        if ($params['af_reason_id'] == 0) {
                            // 不支持无理由
                            if (!in_array($params['af_reason_id'], array_column($af_reason_list, 'id'))) {
                                throw new BusinessException(ErrorCode::NORMAL_ERROR, '不支持无理由退款');
                            } else {
                                // 超过无理由售后期限
                                if ($p['can_af_apply_duration'] != -1 && ($p['af_no_reason_duration'] * 86400 + $p['paid_time'] < time())) {
                                    throw new BusinessException(ErrorCode::NORMAL_ERROR, '超过无理由退款期限');
                                }
                            }
                        } else {
                            if (!in_array($params['af_reason_id'], array_column($af_reason_list, 'id'))) {
                                throw new BusinessException(ErrorCode::NORMAL_ERROR, '未知售后原因');
                            } else {
                                // 超过售后期限
                                if ($p['can_af_apply_duration'] != -1 && ($p['can_af_apply_duration'] * 86400 + $p['paid_time'] < time())) {
                                    throw new BusinessException(ErrorCode::NORMAL_ERROR, '超过售后服务期限');
                                }
                            }
                        }
                    }

                    // 支持售后类型 售后时限 无理由时限
                    $af_types = explode(',', trim($p['support_af_types'], ','));
                    if (empty($af_types) || !in_array($params['af_type'], $af_types)) {
                        throw new BusinessException(ErrorCode::NORMAL_ERROR, '不支持的售后类型');
                    }

                    // 阶梯价商品必须一次性全退
                    if ($p['is_step_price'] == 1 && $sku_quantity[$p['sku_id']] != $p['quantity'] && in_array($params['af_type'], [1, 2])) {
                        throw new BusinessException(ErrorCode::NORMAL_ERROR, '阶梯价商品不支持部分退款');
                    }
                }

                // 可申请数量不足
                if ($sku_quantity[$p['sku_id']] > $p['free_num']) {
                    throw new BusinessException(ErrorCode::NORMAL_ERROR, '售后申请数量错误');
                }
                $p['choose_quantity'] = $sku_quantity[$p['sku_id']];// 申请数量
                // 退款（商品金额=商品金额-优惠券金额）
                if (in_array($params['af_type'], [1, 2])) {
                    // 全退
                    if ($is_all_back) {
                        // 商家责任
                        $p['is_back_delivery'] = 1;
                        $p['is_back_coupon'] = 1;
                        $p['choose_subtotal'] = $p['subtotal'];
                        $p['single_delivery_price'] = $order['delivery_price'] / $order['product_num'];
                        $p['single_coupon_price'] = $order['coupon_price'] / $order['product_num'];
                        // 用户责任退款金额扣除运费：商品金额-运费金额
                        if ($is_send == 1 && AftersaleSetService::DUTY_PARTY_USER == $af_order_info['af_duty_party']) {
                            $p['is_back_coupon'] = 0;// 不退运费
                        }
                    } else {
                        // 部分退
                        $p_res = $this->priceCalculate($is_send,
                            (int)$af_order_info['af_duty_party'],
                            Common::yuan2fen($order['delivery_price']),
                            Common::yuan2fen($p['single_price']),
                            $sku_quantity[$p['sku_id']],
                            Common::yuan2fen($order['coupon_price']),
                            $coupon_can_use,
                            Common::yuan2fen($order['paid_price']),
                            Common::yuan2fen($order['product_price']));

                        $p['is_back_coupon'] = 1;
                        $p['is_back_delivery'] = $p_res['is_back_delivery'];
                        $p['single_coupon_price'] = Common::fen2yuan($p_res['single_coupon_price']);
                        $p['single_delivery_price'] = Common::fen2yuan($p_res['single_delivery_price']);
                        $p['product_price'] = $p['single_price']; // 下单时价格
                        $p['choose_subtotal'] = $p_res['subtotal'];// 运费优惠券计算价格
                        $af_order_info['is_back_coupon'] = $p_res['is_back_coupon'];
                        $af_order_info['is_back_delivery'] = $p_res['is_back_delivery'];
                        // 返还运费总计
                        if ($p_res['is_back_delivery'] == 0) {
                            // 可以加的钱
                            $af_order_info['back_delivery_price'] += $p_res['add_delivery_price'];
                        }
                        $af_order_info['can_back_delivery_price'] += $p_res['add_delivery_price'];
                        // 不扣优惠总计
                        $af_order_info['can_back_coupon_price'] += $p_res['sub_coupon_price'];
                        // 应退款总计
                        $af_order_info['should_refund_price'] += $p['choose_subtotal'];
                        // 计算结束转换为实际金额
                        $p['choose_subtotal'] = Common::fen2yuan($p['choose_subtotal']);
                    }
                    // 退款商品总金额计算
                    $af_order_info['product_total'] += Common::yuan2fen($p['single_price']) * $sku_quantity[$p['sku_id']];
                    // 退款总数量计算
                    $af_order_info['product_num'] += $sku_quantity[$p['sku_id']];
                }
                $af_order_info['products'][] = $p;
            }
        }
        // 有商品订单金额转换
        if ($order['order_style'] == 1 || $order['order_style'] == 3) {
            $af_order_info['product_total'] = Common::fen2yuan($af_order_info['product_total']);
            $af_order_info['back_delivery_price'] = Common::fen2yuan($af_order_info['back_delivery_price']);
            $af_order_info['back_coupon_price'] = Common::fen2yuan($af_order_info['back_coupon_price']);
            $af_order_info['can_back_coupon_price'] = Common::fen2yuan($af_order_info['can_back_coupon_price']);
            $af_order_info['can_back_delivery_price'] = Common::fen2yuan($af_order_info['can_back_delivery_price']);
        } else {
            $af_order_info['product_total'] = $order['paid_price'];// 订座没有其他金额
        }

        // 统一返回参数（全退计算）
        if (in_array($params['af_type'], [1, 2]) && $is_all_back) {
            // 全退处理 - 用户责任+已发货= （支付金额 - 扣除运费）
            if (AftersaleSetService::DUTY_PARTY_USER == $af_order_info['af_duty_party'] && $is_send) {
                $af_order_info['is_back_delivery'] = 0;
                $af_order_info['back_delivery_price'] = $order['delivery_price'];
                $af_order_info['should_refund_price'] = Common::fen2yuan(Common::yuan2fen($order['paid_price']) - Common::yuan2fen($order['delivery_price']));
            } else {
                $af_order_info['back_delivery_price'] = 0;// 退还运费金额
                $af_order_info['should_refund_price'] = $order['paid_price'];
            }
            $af_order_info['can_back_coupon_price'] = $order['coupon_price'];
            $af_order_info['can_back_delivery_price'] = $order['delivery_price'];
        } else {
            // 部分退应退金额
            $af_order_info['should_refund_price'] = Common::fen2yuan($af_order_info['should_refund_price']);
        }
        return $af_order_info;
    }

    /**
     * 检测订单已退款数量
     * @param int $order_id
     * @return array
     */
    public function checkRefunded(int $order_id): array
    {
        return $this->getModelInstance()
            ->where(['order_id' => $order_id, 'af_status' => self::STATUS_FINISHED])
            ->select([Db::raw("sum('product_num') as product_num"),
                Db::raw('sum(can_back_coupon_price*100) as total_back_coupon_price'),
                Db::raw('sum(can_back_delivery_price*100) as total_back_delivery_price')])
            ->first()->toArray();
    }

    /**
     * 部分退商品金额计算 计算单位：分 （退还运费:加钱  不扣优惠：减钱）（不扣优惠 || 退运费：1）（否则为0）
     * @param $is_send bool 是否发货
     * @param $duty_party int 责任方 1卖家 2卖家
     * @param int $delivery_price double 订单运费金额
     * @param int $product_single double 商品下单单价
     * @param $a_quantity int 售后退款申请数量
     * @param int $coupon_price double 订单优惠券金额
     * @param bool $coupon_can_use 优惠券是否还适用
     * @param int $paid_price 实际支付金额
     * @param int $product_price 订单商品总金额
     * @return array
     */
    public function priceCalculate(bool $is_send, int $duty_party, int $delivery_price, int $product_single, int $a_quantity, int $coupon_price, bool $coupon_can_use, int $paid_price, int $product_price): array
    {
        // 商品 100  数量10 商品单价10  运费10（用户责任+发货） 优惠券15 支付95
        // 商品实际支付金额：（支付金额-运费金额）
        // 退款金额所占比例：（(商品单价*数量)/商品总额）
        // 公式：(商品实际金额 * 退款金额所占比例) + 扣除运费 * 退款金额所占比例 - 优惠券 * 退款金额所占比例
        // 85*((5*10)/100) + 0 - 15*((5*10)/100) = 32.5

        // 扣除退货商品后的订单商品->验证优惠券是否仍然可用 todo
        $is_back_coupon = 1;// 不扣优惠券
        $is_back_delivery = 0; // 退运费（退运费、不扣优惠券）

        // 商品实际支付金额
        $actually_pay_price = $paid_price - $delivery_price;
        var_dump("商品实际支付金额：" . $actually_pay_price);
        // 退款商品金额占比:提高百分比精度为四舍五入2位小数
        $percent = round(($a_quantity * $product_single) / $product_price, 2);
        var_dump("退款商品金额占总商品金额比例：" . $percent);
        // 退款商品金额占总金额比例 - 含优惠券一起退
        $actually_pay_price = $actually_pay_price * $percent;
        // 退款商品实际金额
        var_dump("退款实际商品金额：" . $actually_pay_price);

        // 运费优惠券小计
        $delivery_total = $delivery_price * $percent;
        $coupon_total = $coupon_price * $percent;
        // 运费优惠券每个商品均摊金额
        $single_coupon_price = $coupon_total / $a_quantity;// 单个应退优惠券金额
        $single_delivery_price = $delivery_total / $a_quantity;//单个应退运费金额

        // 商家责任 || 用户责任+未发货
        if ($duty_party == AftersaleSetService::DUTY_PARTY_SHOP || (!$is_send && $duty_party == AftersaleSetService::DUTY_PARTY_USER)) {
            $actually_pay_price += $delivery_price * $percent;
            $is_back_delivery = 1;
        }

        return [
            'is_back_coupon' => $is_back_coupon,// 1不扣优惠券 0扣优惠
            'sub_coupon_price' => (int)$coupon_total, // 扣除优惠金额
            'add_delivery_price' => (int)$delivery_total, // 退还运费金额
            'single_coupon_price' => (int)$single_coupon_price,// 均摊优惠券金额
            'single_delivery_price' => (int)$single_delivery_price, // 均摊运费金额
            'is_back_delivery' => $is_back_delivery,// 1退还运费 0不退运费
            'subtotal' => (int)$actually_pay_price
        ];
    }

    /**
     * 生成售后单号
     * @param string|null $prefix
     * @return string
     */
    public function generateSN($prefix = "AF"): string
    {
        try {
            $generator = ApplicationContext::getContainer()->get(IdGeneratorInterface::class);
            $id = $generator->generate();
        } catch (NotFoundExceptionInterface $e) {
            echo $e->getMessage();
            throw new BusinessException(ErrorCode::NORMAL_ERROR);
        } catch (ContainerExceptionInterface $e) {
            echo $e->getMessage();
            throw new BusinessException(ErrorCode::NORMAL_ERROR);
        } catch (\Throwable $exception) {
            echo $exception->getMessage();
            throw new BusinessException(ErrorCode::NORMAL_ERROR);
        }
        return $prefix . "" . date("Ym") . substr(strval($id), 8) . rand(10000, 99999);
    }

    /**
     * 确认售后
     * @param int $user_id
     * @return array
     */
    public function aftersaleConfirm(int $user_id): array
    {
        return $this->aftersaleVerify($user_id, false);
    }

    /**
     * 申请售后 返回售后单号
     * @param int $user_id
     * @return string
     */
    public function aftersaleApply(int $user_id): string
    {
        $data = $this->aftersaleVerify($user_id);
        $products = $data['products'];
        $table_filter = ['af_sn', 'af_type', 'order_id', 'shop_id', 'user_id', 'apply_time', 'should_refund_price', 'is_back_coupon', 'is_back_delivery', 'back_coupon_price',
            'back_delivery_price', 'voucher', 'af_reason_id', 'af_reason', 'af_order_style', 'can_back_coupon_price', 'can_back_delivery_price', 'product_total', 'product_num', 'af_duty_party', 'is_delivery', 'coupon_can_use', 'is_all_back', 'desc', 'back_type', 'user_address_id', 'shop_address_id'];
        $af_data = array_filter($data, function ($key) use ($table_filter) {
            if (!in_array($key, $table_filter)) {
                return false;
            } else {
                return true;
            }
        }, ARRAY_FILTER_USE_KEY);

        // 非商品售后不需商品验证
        if ($data['af_order_style'] != 2 && empty($products)) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, '无可用商品');
        }
        // 物流、配送商家未发货无法申请退货退款
        $order_instance = $this->order->getInstance()->find($data['order_id']);
        if (in_array($order_instance->delivery_type, [ShopDeliveryConfigService::TYPE_EXPRESS, ShopDeliveryConfigService::TYPE_LOCAL]) &&
            $order_instance->order_status == FlyOrderService::STATUS_WAIT_RECEIVE &&
            empty($order_instance->delivery_id) &&
            in_array($data['af_type'], [self::TYPE_REFUND_P, self::TYPE_SWAP, self::TYPE_REPAIR])) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, '商家未发货无法申请');
        }
        $food_params = [];
        $auto_pass = false;
        // 订座
        if ($order_instance->order_style == 2) {
            // 用餐前多少分钟直接退
            if ($order_instance->seat_can_af_end_time > 0 && $order_instance->seat_can_af_end_time <= time()) {
                $auto_pass = true;
            } elseif ($order_instance->order_status == FlyOrderService::STATUS_WAIT_RECEIVE) {
                // 未核销直接可退
                $auto_pass = true;
            }
        } elseif ($order_instance->order_style == 3) {
            // 点餐
            if ($order_instance->order_status == FlyOrderService::STATUS_WAIT_RECEIVE) {
                $auto_pass = true;
            }
        }

        try {
            Db::beginTransaction();
            $af_instance = $this->getModelInstance();

            // 仅退款
            if ($af_data['af_type'] == 1) {
                //
                if (in_array($data['order_details']['delivery_type'], [ShopDeliveryConfigService::TYPE_EXPRESS, ShopDeliveryConfigService::TYPE_LOCAL])) {
                    // 未发货
                    if ($data['order_details']['delivery_id'] == 0) {
                        $re = $this->pay->refund('', 0.00);// todo 直接退款
                        if (!$re) {
                            Db::rollBack();
                            throw new BusinessException(ErrorCode::NORMAL_ERROR, '退款失败');
                        }
                        // 售后单完成
                        $af_instance->af_status = self::STATUS_FINISHED;
                        $af_instance->is_refund = 1;
                        $af_instance->refund_price = $af_data['should_refund_price'] ?? 0;
                        $af_instance->refund_time = time();
                        $af_instance->finish_time = time();
                    }
                } elseif ($auto_pass) {
                    // 没事订单不需审核的售后单
                    $re = $this->pay->refund('', 0.00);// todo 直接退款
                    if (!$re) {
                        Db::rollBack();
                        throw new BusinessException(ErrorCode::NORMAL_ERROR, '退款失败');
                    }
                    // 售后单完成
                    $af_instance->af_status = self::STATUS_FINISHED;
                    $af_instance->is_refund = 1;
                    $af_instance->refund_price = $af_data['should_refund_price'] ?? 0;
                    $af_instance->refund_time = time();
                    $af_instance->finish_time = time();
                }
            } else {
                $af_instance->af_status = self::STATUS_WAIT_CHECK;
            }
            foreach ($af_data as $field => $val) {
                $af_instance->$field = $val;
            }
            if (!$af_instance->save()) {
                throw new BusinessException(ErrorCode::NORMAL_ERROR, '申请失败');
            }
            $products_info = [];
            foreach ($products as $p) {
                $products_info[] = [
                    'af_id' => $af_instance->af_id,
                    'order_id' => $data['order_id'],
                    'order_p_id' => $p['id'],
                    'is_back_coupon' => $p['is_back_coupon'],
                    'single_coupon_price' => $p['single_coupon_price'],
                    'single_delivery_price' => $p['single_delivery_price'],
                    'is_back_delivery' => $p['is_back_delivery'],
                    'product_price' => $p['single_price'],
                    'sku_id' => $p['sku_id'],
                    'quantity' => $p['choose_quantity'],
                    'subtotal' => $p['choose_subtotal'] ?? 0
                ];
                // 修改可申请数量
                make(FlyOrderProduct::class)
                    ->where(['id' => $p['id']])
                    ->where('free_num', '>=', $p['choose_quantity'])
                    ->update(['free_num' => Db::raw('free_num-' . $p['choose_quantity'])]);
            }
            make(AftersaleProduct::class)->insert($products_info);

            $order_details = $this->order->getDetails($af_data['user_id'], $af_data['order_id']);
            $order_instance->curr_af_id = $af_instance->af_id;
            // 当前售后完成-直接退款 - 当前直接退判断全部退
            if ($order_details['order_style'] == 2 && $auto_pass) {
                $order_instance->refund_price = $af_instance->refund_price; // 更新订单退款金额
                // 订座退了后就关闭了订单：待使用订单改为已完成：关闭订单
                if ($order_instance->order_status == FlyOrderService::STATUS_WAIT_RECEIVE) {
                    $order_instance->order_status = FlyOrderService::STATUS_FINISHED;
                    $order_instance->close_time = time();
                }
                // 点餐或电商订单,订单完成更新退款金额
            } elseif ($af_instance->af_status == self::STATUS_FINISHED && $this->getSuccessBackNum($data['order_id']) == array_sum(array_column($order_details['with_products'], 'quantity'))) {
                $order_instance->refund_price = Db::raw("refund_price+" . $af_instance->refund_price);// 更新订单已退款金额
                // 已退完：待收货状态改为已完成：关闭订单
                if ($order_instance->order_status == FlyOrderService::STATUS_WAIT_RECEIVE) {
                    $order_instance->order_status = FlyOrderService::STATUS_FINISHED;
                    $order_instance->close_time = time();
                }
            }
            // 修改订单绑定售后单 或 全部退款关闭售后单
            $order_instance->save();
        } catch (\Throwable $exception) {
            print_r($exception->getMessage());
            Db::rollBack();
            throw new BusinessException(ErrorCode::NORMAL_ERROR, '申请失败2');
        }
        Db::commit();
        return $af_instance->af_sn;// 返回售后单号
    }

    /**
     * 获取订单已成功退款数量
     * @param int $order_id
     * @return int
     */
    public function getSuccessBackNum(int $order_id): int
    {
        $num = $this->getModelInstance()
            ->leftJoin('fly_aftersale_products', 'fly_aftersale.af_id', '=', 'fly_aftersale_products.af_id')
            ->where(['fly_aftersale.af_status' => self::STATUS_FINISHED, 'fly_aftersale.order_id' => $order_id])
            ->whereIn('fly_aftersale.af_type', [self::TYPE_REFUND, self::TYPE_REFUND_P])
            ->sum('quantity');
        return (int)$num;
    }

    /**
     * 获取售后详情
     * @param string $af_sn
     * @param int $user_id
     * @return array
     */
    public function afDetails(string $af_sn, int $user_id): array
    {
        // 售后单
        $af_instance = $this->getModelInstance()
            ->with(['with_order', 'with_products', 'with_shop_address', 'with_shop_change_address'])
            ->where('user_id', '=', $user_id)
            ->where('af_sn', '=', $af_sn)
            ->first();
        if (empty($af_instance)) {
            return [];
        }
        $af_arr = $af_instance->toArray();
        $af_arr['user_response_company_name'] = (DeliverySendService::DELIVERY)[$af_arr['user_response_company']] ?? "";
        $af_arr['count_down'] = "";
        $af_sets = $this->afSet->getTimeTypeSet(1);
        $af_sets_days = array_column($af_sets, 'days', 'time_type');
        // 回传单号时限：需要回传单号的
        if ($af_arr['af_status'] == 2 && in_array($af_arr['af_type'], [AftersaleService::TYPE_REFUND_P, AftersaleService::TYPE_SWAP, AftersaleService::TYPE_REPAIR])) {
            if (empty($af_arr['user_response_sn'])) {
                // 回传单号前自动关闭时限
                $dur = $af_arr['check_time'] + 86400 * $af_sets_days[AftersaleSetService::TIME_TYPE_USER_RESPONSE] - time();
                $dur = $dur < 0 ? 0 : $dur;
            } else {
                // 回传单号后自动退款时限
                $dur = $af_arr['user_response_time'] + 86400 * $af_sets_days[AftersaleSetService::TIME_TYPE_AUTO_REFUND] - time();
                $dur = $dur < 0 ? 0 : $dur;
            }
            $count_arr = Common::formatSecondDuration($dur);
            $af_arr['count_down'] = $count_arr['day'] . "天" . $count_arr['hour'] . "小时" . $count_arr['min'] . "分";
        }

        return $af_arr;
    }

    /**
     * 撤销售后申请
     * @param int $user_id
     * @param string $af_sn
     * @param int|null $by_outer 0用户自己取消 1其他因素取消
     * @return bool
     */
    public function afCancel(int $user_id, string $af_sn, $by_outer = 0): bool
    {
        try {
            Db::beginTransaction();
            if (empty($by_outer)) {
                $af_instance = $this->getModelInstance()->where('af_status', '=', self::STATUS_WAIT_CHECK)->where('af_sn', '=', $af_sn)->first();
            } else {
                $af_instance = $this->getModelInstance()
                    ->where('user_response_time', '=', 0)
                    ->where('af_status', '=', self::STATUS_CHECKED)
                    ->where('af_sn', '=', $af_sn)->first();
            }
            if (empty($af_instance) || $af_instance->user_id != $user_id) {
                Db::rollBack();
                throw new BusinessException(ErrorCode::NORMAL_ERROR, '售后单不存在');
            }
            $af_instance->af_status = self::STATUS_CANCEL;
            $af_instance->check_time = time();
            $af_instance->finish_time = time();
            if (!$af_instance->save()) {
                Db::rollBack();
                return false;
            }
            // 解锁可申请售后数量
            $af_p_num = make(AftersaleProduct::class)->where([
                'af_id' => $af_instance->af_id
            ])->pluck('quantity', 'order_p_id');

            foreach ($af_p_num as $id => $quantity) {
                print_r($quantity);
                make(FlyOrderProduct::class)->where([
                    'id' => $id
                ])->whereRaw('free_num<=' . $quantity)
                    ->update(['free_num' => Db::raw('free_num+' . $quantity)]);
            }
        } catch (\Throwable $exception) {
            Db::rollBack();
            echo $exception->getMessage();
            return false;
        }
        Db::commit();
        return true;
    }

    /**
     * 用户回传单号
     * @param $user_id
     * @return bool
     */
    public function responseSN($user_id): bool
    {
        $params = $this->request->inputs(['user_response_company', 'user_response_sn', 'af_sn']);
        if (empty($params['user_response_company']) || empty($params['user_response_sn']) || empty($params['af_sn'])) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, '缺少参数');
        }
        if (!in_array($params['user_response_company'], array_keys(DeliverySendService::DELIVERY))) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, '物流类型错误');
        }
        $af_instance = $this->getModelInstance()
            ->where('af_sn', '=', $params['af_sn'])
            ->where('user_id', '=', $user_id)
            ->first();

        if ($af_instance->af_status != self::STATUS_CHECKED && !empty($af_instance->user_response_sn)) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, '状态错误');
        }
        // 无需退货
        if (!in_array($af_instance->af_type, [self::TYPE_REFUND_P, self::TYPE_SWAP, self::TYPE_REPAIR])) {
            throw new BusinessException(ErrorCode::NORMAL_ERROR, '无需退货');
        }

        $af_instance->user_response_time = time();
        $af_instance->user_response_sn = $params['user_response_sn'];
        $af_instance->user_response_company = $params['user_response_company'];
        if (!$af_instance->save()) {
            return false;
        }
        return true;
    }
}